// @Author EthanScriptOn
// @Desc
package tool

import (
	"errors"
	"fmt"
	"gitee.com/fatzeng/srf_switch_basic_components/util"
	"sync"
)

// SyncSlice Synchronized collections are similar sync.Map
type SyncSlice struct {
	slice []interface{}
	mu    sync.RWMutex
}

func GenerateSyncSlice() *SyncSlice {
	return &SyncSlice{
		slice: make([]interface{}, 0),
		mu:    sync.RWMutex{},
	}
}

// GetFirst Gets the first element of the collection
func (s *SyncSlice) GetFirst() (interface{}, error) {
	return s.Get(func(slice []interface{}) interface{} {
		return slice[0]
	})
}

// ForEach ForEach the collection element
func (s *SyncSlice) ForEach(option func(interface{}) (bool, error)) error {
	if option == nil {
		return errors.New("option is nil")
	}
	return LockWithSync(s.mu.RLock, s.mu.RUnlock, func() error {
		for _, item := range s.slice {
			if interrupt, err := option(item); err != nil {
				return err
			} else if interrupt {
				return nil
			}
		}
		return nil
	})
}

// ForEach ForEach the collection element(mutex)
func (s *SyncSlice) ForEachWithMutex(option func(interface{}) (bool, error)) error {
	if option == nil {
		return errors.New("option is nil")
	}
	return LockWithSync(s.mu.Lock, s.mu.Unlock, func() error {
		for _, item := range s.slice {
			if interrupt, err := option(item); err != nil {
				return err
			} else if interrupt {
				return nil
			}
		}
		return nil
	})
}

// Get Get the collection element
func (s *SyncSlice) Get(option func([]interface{}) interface{}) (interface{}, error) {
	var result interface{} = nil
	if option == nil {
		return result, errors.New("option is nil")
	}
	return result, LockWithSync(s.mu.RLock, s.mu.RUnlock, func() error {
		if len(s.slice) <= 0 {
			return nil
		}
		result = option(s.slice)
		return nil
	})
}

// GetLast Gets the last element of the collection
func (s *SyncSlice) GetLast() (interface{}, error) {
	return s.Get(func(slice []interface{}) interface{} {
		return slice[len(slice)-1]
	})
}

// Remove Delete the collection element
func (s *SyncSlice) Remove(option func(int, interface{}) bool) error {
	if option == nil {
		return errors.New("option is nil")
	}
	return LockWithSync(s.mu.Lock, s.mu.Unlock, func() error {
		if len(s.slice) <= 0 {
			return nil
		}
		newSlice, err := util.RemoveSliceCustomized(s.slice, option)
		if err != nil {
			return err
		}
		s.slice = newSlice.([]interface{})
		return nil
	})
}

// RemoveLast Remove the last element
func (s *SyncSlice) RemoveLast() error {
	return s.Remove(func(index int, item interface{}) bool {
		return index == len(s.slice)-1
	})
}

// RemoveFirst Remove the first element
func (s *SyncSlice) RemoveFirst() error {
	return s.Remove(func(index int, item interface{}) bool {
		return index == 0
	})
}

// Add Add a collection element
func (s *SyncSlice) Add(item interface{}) error {
	if item == nil {
		return errors.New("add item is nil")
	}
	return LockWithSync(s.mu.Lock, s.mu.Unlock, func() error {
		s.slice = append(s.slice, item)
		return nil
	})
}

func (s *SyncSlice) Print() string {
	str := ""
	_ = LockWithSync(s.mu.Lock, s.mu.Unlock, func() error {
		for _, i := range s.slice {
			if i != nil {
				str += fmt.Sprintf("%v,", i)
			}
		}
		return nil
	})
	return str
}
